%%%---------------------------------------------------------------------------------------
%%% @author     Stuart Jackson <simpleenigma@gmail.com> [http://erlsoft.org]
%%% @copyright  2006 - 2007 Simple Enigma, Inc. All Rights Reserved.
%%% @doc        ERML command processing
%%% @reference  See <a href="http://erlsoft.org/modules/erlweb" target="_top">Erlang Software Framework</a> for more information
%%% @reference See <a href="http://erlweb.googlecode.com" target="_top">ErlWeb Google Code Repository</a> for more information
%%% @version    0.0.2
%%% @since      0.0.1
%%% @end
%%%
%%%
%%% The MIT License
%%%
%%% Copyright (c) 2007 Stuart Jackson, Simple Enigma, Inc. All Righs Reserved
%%%
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
%%% of this software and associated documentation files (the "Software"), to deal
%%% in the Software without restriction, including without limitation the rights
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
%%% copies of the Software, and to permit persons to whom the Software is
%%% furnished to do so, subject to the following conditions:
%%%
%%% The above copyright notice and this permission notice shall be included in
%%% all copies or substantial portions of the Software.
%%%
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
%%% THE SOFTWARE.
%%%
%%%
%%%---------------------------------------------------------------------------------------
-module(erml_cmd).
-author('sjackson@simpleenigma.com').
-include("../include/erml.hrl").
-include_lib("xmerl/include/xmerl.hrl").

-export([command/2,name_prefix/1]).
-export([var/2,if_var_sub/2,var_sub/2,contains_variable/1]).
-export([internal_set/3]).
-export([clean_erml/1,read_erml/1,check_erml/1]).


%%-------------------------------------------------------------------------
%% @spec (FileName::string()) -> {true,String::string()} | false
%% @doc  Reads FileName and checks for ERML commands.
%% @end
%%-------------------------------------------------------------------------
check_erml(FileName) ->
	String = read_erml(FileName),
	case regexp:match(String,?ERML_REGEXP) of
		nomatch -> false;
		{match,_,_} -> {true,String}
	end.

%%-------------------------------------------------------------------------
%% @spec (XHTML::string()) -> Clean::string()
%% @doc  Removes references to ermlcommand from string. This is a clean up 
%%		step that allows commands to be removed from the XHTML
%% @end
%%-------------------------------------------------------------------------
clean_erml(XHTML) ->
	{ok,Clean1,_} = regexp:gsub(XHTML,"<ermlcommand(.)*>",""),
	{ok,Clean,_} = regexp:gsub(Clean1,"</ermlcommand>",""),
	Clean.

%%-------------------------------------------------------------------------
%% @spec (Element::xmlelement(),ERML::any()) -> {xmlelement(),ERML::any()}
%% @doc  Process XML Elements and build ERML commands
%% @end
%%-------------------------------------------------------------------------
command(Element,ERML) ->
	io:format("ERML Command: ~p~n",[Element#xmlElement.name]),
	case lists:keysearch(Element#xmlElement.name,1,erml_ext:all()) of
		{value,{Command,Module}} -> Module:Command(Element,ERML);
		_ -> {#xmlElement{name=ermlcommand},ERML}
	end.

%%-------------------------------------------------------------------------
%% @spec (Text::string()) -> true | false
%% @doc  Checks string or XMLElement for any potential variables
%% @end
%%-------------------------------------------------------------------------
contains_variable(Element) when is_record(Element,xmlElement) -> false;
contains_variable(Text) when is_record(Text,xmlText) -> 
	case regexp:match(Text#xmlText.value,?VAR_REGEXP) of
		{match,_,_} -> true;
		_ -> false
	end;
contains_variable(_Element) -> false.

%%-------------------------------------------------------------------------
%% @spec (Value::any(),ERML::erml_record()) -> String::any()
%% @doc  Checks to see if there are varaibles in an IF statement condition.
%% @end
%%-------------------------------------------------------------------------
if_var_sub(Value,ERML) ->
	case regexp:match(Value,?VAR_SHORT_REGEXP) of
		{match,_,_} -> var_sub(Value,ERML#erml.var);
		_ -> Value
	end.

%%-------------------------------------------------------------------------
%% @spec (ERML::erml_record(),Key::atom(),Value::any()) -> ERML::erml_record()
%% @doc  Sets a variable named Key to Value in the ERML record. This is used
%%		as an internal set funcations that allows the settings or changing
%%		of variable values without using the ERMLSET command. The ERMLSET
%%		command uses this funcation to set it's values.
%% @end
%%-------------------------------------------------------------------------
internal_set(ERML,List,Value) when is_list(List) -> internal_set(ERML,list_to_atom(List),Value);
internal_set(ERML,Key,Value) ->
%	NewValue = erml_eval:eval(Value),
	VarList = [{Key,simplify_value(Value)}|proplists:delete(Key,ERML#erml.var)],
	ERML#erml{var=lists:ukeysort(1,VarList)}.

%%-------------------------------------------------------------------------
%% @spec (Name::string()) -> String::string()
%% @doc  Returns the first 4 characters of a given term. Accepted terms are 
%%		xmlElement, xmlText, atom and list/string.
%% @end
%%-------------------------------------------------------------------------
name_prefix(XML) when is_record(XML,xmlElement) -> name_prefix(XML#xmlElement.name);
name_prefix(XML) when is_record(XML,xmlText) -> name_prefix(XML#xmlText.type);
name_prefix(Atom) when is_atom(Atom) -> name_prefix(atom_to_list(Atom));
name_prefix(Name) when is_list(Name) -> string:left(Name,4).

%%-------------------------------------------------------------------------
%% @spec (FileName::string()) -> String::string()
%% @doc  Reads a FileName and returns contents as a string
%% @end
%%-------------------------------------------------------------------------
read_erml(FileName) ->
	case file:read_file(FileName) of
		{ok,Bin} -> binary_to_list(Bin);
		_ -> error
	end.

simplify_value(Value) when is_list(Value) ->
	case string:to_integer(Value) of
		{Int,[]} when is_integer(Int) -> Int;
		_ -> 
			case string:to_float(Value) of
				{Float,[]} when is_float(Float) -> Float;
				_ -> Value
			end
	end;
simplify_value(Value) -> Value.


to_string(Integer) when is_integer(Integer) -> integer_to_list(Integer);
to_string(Atom) when is_atom(Atom) -> atom_to_list(Atom);

to_string(List) when is_list(List) -> List.

%%-------------------------------------------------------------------------
%% @spec (XMLElement::xml(),ERML::erml_record()) -> XMLElement::xml()
%% @doc  Processes all variables and inserts them into the XML Element
%% @end
%%-------------------------------------------------------------------------
var(Element,ERML) when is_record(ERML,erml) -> 
	{_,String} = lists:mapfoldl(
		fun(X,S) -> 
			{Atom,Value} = X,
			case regexp:gsub(S,"%" ++ to_string(Atom) ++ "%",to_string(Value)) of
				{ok,NewS,_} -> ok;
				_ -> NewS = S
			end,
%			io:format("~p ~p~n",[X,NewS]), 
			{Atom,NewS}
		end,
		Element#xmlText.value,erml_eval:build_var(ERML)),
	Element#xmlText{value=String}.

%%-------------------------------------------------------------------------
%% @spec (VarName::string(),VarList::list()) -> Term::any()
%% @doc  
%% @hidden
%% @end
%%-------------------------------------------------------------------------
var_sub(VarName,VarList) when is_list(VarName) -> var_sub(list_to_atom(VarName),VarList);
var_sub(VarName,VarList) -> 
	case lists:keysearch(VarName,1,VarList) of
		{value,{_Key,Value}} -> Value;
		_ -> VarName
	end.